using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Services;
using Volo.Abp.EntityFrameworkCore;
using Matrix.Notification.Domain.Notifications;
using Matrix.Notification.EntityFrameworkCore;

namespace Matrix.Notification.HttpApi.Host.HealthChecks;

/// <summary>
/// 通知服务健康检查
/// </summary>
public class NotificationHealthCheck : IHealthCheck, ITransientDependency
{
    private readonly ILogger<NotificationHealthCheck> _logger;
    private readonly IDbContextProvider<NotificationDbContext> _dbContextProvider;
    private readonly INotificationRepository _notificationRepository;
    private readonly INotificationTemplateRepository _templateRepository;
    private readonly INotificationSubscriptionRepository _subscriptionRepository;

    public NotificationHealthCheck(
        ILogger<NotificationHealthCheck> logger,
        IDbContextProvider<NotificationDbContext> dbContextProvider,
        INotificationRepository notificationRepository,
        INotificationTemplateRepository templateRepository,
        INotificationSubscriptionRepository subscriptionRepository)
    {
        _logger = logger;
        _dbContextProvider = dbContextProvider;
        _notificationRepository = notificationRepository;
        _templateRepository = templateRepository;
        _subscriptionRepository = subscriptionRepository;
    }

    public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var stopwatch = Stopwatch.StartNew();
        var data = new Dictionary<string, object>
        {
            ["checkTime"] = DateTime.UtcNow,
            ["serviceName"] = "Matrix.Notification"
        };

        try
        {
            _logger.LogDebug("开始执行通知服务健康检查");

            // 1. 检查数据库连接
            await CheckDatabaseConnectionAsync(cancellationToken, data);

            // 2. 检查通知表访问
            await CheckNotificationTableAccessAsync(cancellationToken, data);

            // 3. 检查模板表访问
            await CheckTemplateTableAccessAsync(cancellationToken, data);

            // 4. 检查订阅表访问
            await CheckSubscriptionTableAccessAsync(cancellationToken, data);

            // 5. 检查待处理通知统计
            await CheckPendingNotificationsCountAsync(cancellationToken, data);

            stopwatch.Stop();
            data["duration"] = stopwatch.ElapsedMilliseconds;

            _logger.LogInformation("通知服务健康检查完成，耗时: {Duration}ms", stopwatch.ElapsedMilliseconds);

            return HealthCheckResult.Healthy("通知服务运行正常", data);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            data["duration"] = stopwatch.ElapsedMilliseconds;
            data["error"] = ex.Message;

            _logger.LogError(ex, "通知服务健康检查失败，耗时: {Duration}ms", stopwatch.ElapsedMilliseconds);

            return HealthCheckResult.Unhealthy("通知服务异常", ex.Message, data);
        }
    }

    /// <summary>
    /// 检查数据库连接
    /// </summary>
    private async Task CheckDatabaseConnectionAsync(CancellationToken cancellationToken, Dictionary<string, object> data)
    {
        try
        {
            var stopwatch = Stopwatch.StartNew();
            var dbContext = await _dbContextProvider.GetDbContextAsync(cancellationToken);

            // 尝试连接数据库
            await dbContext.Database.CanConnectAsync(cancellationToken);

            stopwatch.Stop();
            data["databaseConnection"] = "healthy";
            data["databaseConnectionTime"] = stopwatch.ElapsedMilliseconds;

            _logger.LogDebug("数据库连接检查通过，耗时: {Duration}ms", stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            data["databaseConnection"] = "unhealthy";
            data["databaseConnectionError"] = ex.Message;
            throw new UserFriendlyException("数据库连接失败", ex.Message);
        }
    }

    /// <summary>
    /// 检查通知表访问
    /// </summary>
    private async Task CheckNotificationTableAccessAsync(CancellationToken cancellationToken, Dictionary<string, object> data)
    {
        try
        {
            var stopwatch = Stopwatch.StartNew();

            // 尝试查询通知表记录数
            var count = await _notificationRepository.GetCountAsync(cancellationToken: cancellationToken);

            stopwatch.Stop();
            data["notificationsTableAccess"] = "healthy";
            data["notificationsTableAccessTime"] = stopwatch.ElapsedMilliseconds;
            data["totalNotifications"] = count;

            _logger.LogDebug("通知表访问检查通过，记录数: {Count}，耗时: {Duration}ms", count, stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            data["notificationsTableAccess"] = "unhealthy";
            data["notificationsTableAccessError"] = ex.Message;
            throw new UserFriendlyException("通知表访问失败", ex.Message);
        }
    }

    /// <summary>
    /// 检查模板表访问
    /// </summary>
    private async Task CheckTemplateTableAccessAsync(CancellationToken cancellationToken, Dictionary<string, object> data)
    {
        try
        {
            var stopwatch = Stopwatch.StartNew();

            // 尝试查询模板表记录数
            var count = await _templateRepository.GetCountAsync(cancellationToken: cancellationToken);

            stopwatch.Stop();
            data["templatesTableAccess"] = "healthy";
            data["templatesTableAccessTime"] = stopwatch.ElapsedMilliseconds;
            data["totalTemplates"] = count;

            _logger.LogDebug("模板表访问检查通过，记录数: {Count}，耗时: {Duration}ms", count, stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            data["templatesTableAccess"] = "unhealthy";
            data["templatesTableAccessError"] = ex.Message;
            throw new UserFriendlyException("模板表访问失败", ex.Message);
        }
    }

    /// <summary>
    /// 检查订阅表访问
    /// </summary>
    private async Task CheckSubscriptionTableAccessAsync(CancellationToken cancellationToken, Dictionary<string, object> data)
    {
        try
        {
            var stopwatch = Stopwatch.StartNew();

            // 尝试查询订阅表记录数
            var count = await _subscriptionRepository.GetCountAsync(cancellationToken: cancellationToken);

            stopwatch.Stop();
            data["subscriptionsTableAccess"] = "healthy";
            data["subscriptionsTableAccessTime"] = stopwatch.ElapsedMilliseconds;
            data["totalSubscriptions"] = count;

            _logger.LogDebug("订阅表访问检查通过，记录数: {Count}，耗时: {Duration}ms", count, stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            data["subscriptionsTableAccess"] = "unhealthy";
            data["subscriptionsTableAccessError"] = ex.Message;
            throw new UserFriendlyException("订阅表访问失败", ex.Message);
        }
    }

    /// <summary>
    /// 检查待处理通知统计
    /// </summary>
    private async Task CheckPendingNotificationsCountAsync(CancellationToken cancellationToken, Dictionary<string, object> data)
    {
        try
        {
            var stopwatch = Stopwatch.StartNew();

            // 查询待处理通知数量
            var pendingCount = await _notificationRepository.GetCountAsync(
                status: Domain.Shared.Notifications.NotificationStatus.Pending,
                cancellationToken: cancellationToken);

            var retryableCount = await _notificationRepository.GetCountAsync(
                status: Domain.Shared.Notifications.NotificationStatus.Failed,
                cancellationToken: cancellationToken);

            stopwatch.Stop();
            data["pendingNotifications"] = pendingCount;
            data["retryableNotifications"] = retryableCount;
            data["statisticsCheckTime"] = stopwatch.ElapsedMilliseconds;

            // 如果待处理通知过多，返回降级状态
            if (pendingCount > 10000)
            {
                data["warning"] = "待处理通知数量过多";
                _logger.LogWarning("待处理通知数量过多: {Count}", pendingCount);
            }

            _logger.LogDebug("待处理通知统计检查完成，待处理: {Pending}，可重试: {Retryable}，耗时: {Duration}ms",
                pendingCount, retryableCount, stopwatch.ElapsedMilliseconds);
        }
        catch (Exception ex)
        {
            data["statisticsCheck"] = "unhealthy";
            data["statisticsCheckError"] = ex.Message;
            // 统计检查失败不影响整体健康状态
            _logger.LogWarning(ex, "待处理通知统计检查失败，但不影响服务健康状态");
        }
    }
}